import jwt
from django import http
from django.db.models import Avg
from django.http import JsonResponse
from django.views import View
from rest_framework.generics import ListAPIView
from rest_framework.response import Response

from django_redis import get_redis_connection
from rest_framework.views import APIView
from rest_framework_jwt.views import JSONWebTokenAPIView
from rest_framework_jwt.serializers import JSONWebTokenSerializer, VerificationBaseSerializer
from rest_framework import serializers, viewsets, mixins, status
from django.utils.translation import ugettext as _
from rest_framework_jwt.settings import api_settings

from apps.articles.serializers import ArticleModelSerializer
from apps.users.models import User, Teacher
from apps.users.serializers import UserModelSerializer, TeacherModelSerializer, UserFansModelSerializer, \
    UserFollowingsModelSerializer
from utils.QiNiuAvatar.QiNiuAvatar import QiNiuAvatar
from utils.constants import USER_TYPE_CHOICES, QINIU_DOMAIN
from utils.generate_user_name import get_userNameAndPassword
from utils.jwt_handler import jwt_refresh_decode_handler, jwt_refresh_payload_handler
from utils.my_permission import MyPermission
from utils.notifications import Notification
from utils.paginations import PageNum, LargePageNum

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


class MyJSONWebTokenSerializer(JSONWebTokenSerializer):
    def __init__(self, *args, **kwargs):
        """
        Dynamically add the USERNAME_FIELD to self.fields.
        """
        super(JSONWebTokenSerializer, self).__init__(*args, **kwargs)

        self.fields['mobile'] = serializers.CharField()
        self.fields['code'] = serializers.CharField(allow_blank=True, allow_null=True)
        self.fields['update'] = serializers.BooleanField(default=False, required=False)

    def validate(self, attrs):
        credentials = {
            'mobile': attrs.get('mobile'),
            'code': attrs.get('code'),
            'update': attrs.get('update')
        }
        if credentials.get('mobile') and credentials.get('code') or credentials.get('update'):
            if not credentials.get('update'):
                is_correct = self.verify_sms_code(credentials.get('mobile'), credentials.get('code'))
                if not is_correct:
                    msg = _('您的短信验证码错误')
                    raise serializers.ValidationError(msg)
            try:
                user = User.objects.get(mobile=credentials.get('mobile'))
            except Exception as e:
                while True:
                    user_name = get_userNameAndPassword()
                    count = User.objects.filter(username=user_name).count()
                    if not count:
                        break
                user = User.objects.create(mobile=credentials.get('mobile'), username='用户' + user_name)
            if user:
                if not user.is_active:
                    msg = _('当前账户不可用')
                    raise serializers.ValidationError(msg)
                payload = jwt_payload_handler(user)
                payload_refresh = jwt_refresh_payload_handler(user)
                return {
                    'token': {'token': jwt_encode_handler(payload),
                              'refresh_token': jwt_encode_handler(payload_refresh)},
                    'user': user
                }
        else:
            msg = _('缺少手机号或短信验证码，请确认输入后重新登录')
            raise serializers.ValidationError(msg)

    def verify_sms_code(self, mobile, code):
        redis_conn = get_redis_connection('code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)  # sms_code_server是bytes
        # 判断短信验证码是否过期
        if not sms_code_server:
            return False
        # 对比用户输入的和服务端存储的短信验证码是否一致
        if code != sms_code_server.decode():
            return False
        return True


class MyRefreshJSONWebTokenSerializer(VerificationBaseSerializer):
    token = serializers.CharField(required=False)
    refresh_token = serializers.CharField()

    def validate(self, attrs):
        refresh_token = attrs['refresh_token']
        try:
            payload = jwt_refresh_decode_handler(refresh_token)
        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')
            raise serializers.ValidationError(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')
            raise serializers.ValidationError(msg)
        user = self._check_user(payload=payload)
        new_payload = jwt_payload_handler(user)
        new_refresh_payload = jwt_refresh_payload_handler(user)
        return {
            'token': {'token': jwt_encode_handler(new_payload),
                      'refresh_token': jwt_encode_handler(new_refresh_payload)},
            'user': user
        }


class MyJsonWebTokenAPIView(JSONWebTokenAPIView):
    serializer_class = MyJSONWebTokenSerializer


class MyRefreshJSONWebToken(JSONWebTokenAPIView):
    serializer_class = MyRefreshJSONWebTokenSerializer


class ProfileView(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserModelSerializer


class QiNiuAvatarUploadView(APIView):
    def post(self, request):
        avatar = request.FILES.get('photo')
        mobile = request.POST.get('mobile')
        isContent = request.POST.get('isContent')
        if not avatar:
            return http.JsonResponse({'message': '图片信息获取失败'}, status=400)
        try:
            user = request.user
            if user.mobile != mobile and not isContent:
                raise Exception('手机号用户不匹配')
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '手机号错误'}, status=400)

        avatar_data = avatar.read()
        qn_clint = QiNiuAvatar()
        try:
            ret, info = qn_clint.upload(avatar_data)
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '图片上传失败'}, status=507)
        avatar_url = ret['key']
        if isContent:
            avatar_url = QINIU_DOMAIN + avatar_url
        return http.JsonResponse({'message': 'OK', 'avatar': avatar_url})


class TeacherModelViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModelMixin,
                          mixins.ListModelMixin, mixins.RetrieveModelMixin):
    queryset = Teacher.objects.all()
    serializer_class = TeacherModelSerializer
    pagination_class = PageNum
    permission_classes = [MyPermission]

    def create(self, request, *args, **kwargs):
        try:
            res = super().create(request, *args, **kwargs)
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '申请失败。'})
        user = request.user
        user.type = USER_TYPE_CHOICES[1][0]
        user.save()
        return http.JsonResponse({'message': 'OK', 'data': res.data}, status=status.HTTP_201_CREATED)

    def post(self, request, *args, **kwargs):
        try:
            res = super().update(request, *args, **kwargs)
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '信息修改失败。'})
        return http.JsonResponse({'message': 'OK', 'data': res.data}, headers=res.headers)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        queryset = queryset.annotate(rating_order=Avg('comments__rating')).order_by('-rating_order')
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class LikeTeacherView(APIView):

    def post(self, request, target):
        try:
            teacher = Teacher.objects.get(id=target)
            teacher.like_users.add(request.user)
            teacher.save()
            # 发送点赞通知
            Notification('点赞', request.user, teacher.user).send_system_message()
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '点赞失败'})
        return http.JsonResponse({'message': 'OK'})

    def delete(self, request, target):
        try:
            Teacher.objects.get(id=target).like_users.remove(request.user)
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '取消点赞失败'})
        return http.JsonResponse({'message': 'OK'})


class FollowTeacherView(APIView):

    def post(self, request, target):
        if request.user.id == int(target):
            return http.JsonResponse({'message': '不能关注自己'})
        try:
            teacher = Teacher.objects.get(id=target)
            teacher.fans.add(request.user)
            teacher.user.fans.add(request.user)
            teacher.save()
            # 发送关注通知
            Notification('关注', request.user, teacher.user).send_system_message()
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '关注失败'})
        return http.JsonResponse({'message': 'OK'})

    def delete(self, request, target):
        try:
            teacher = Teacher.objects.get(id=target)
            teacher.fans.remove(request.user)
            teacher.user.fans.remove(request.user)
            teacher.save()
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '取消关注失败'})
        return http.JsonResponse({'message': 'OK'})


class FollowUserView(APIView):

    def post(self, request, target):
        if request.user.id == int(target):
            return http.JsonResponse({'message': '不能关注自己'})
        try:
            target_user = User.objects.get(id=target)
            target_user.fans.add(request.user)
            target_user.save()
            # 发送关注通知
            Notification('关注', request.user, target_user).send_system_message()
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '关注失败'})
        return http.JsonResponse({'message': 'OK'})

    def delete(self, request, target):
        try:
            User.objects.get(id=target).fans.remove(request.user)
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '取消关注失败'})
        return http.JsonResponse({'message': 'OK'})


class UserNameCountView(APIView):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return JsonResponse({'message': 'OK', 'count': count})


class UserRelationListView(ListAPIView):
    queryset = User.objects.all()
    pagination_class = LargePageNum
    permission_classes = [MyPermission]

    def get(self, request, *args, **kwargs):
        key = kwargs.get('user_id')
        type = kwargs.get('type')
        if type == 'fans':
            self.serializer_class = UserFansModelSerializer
            queryset = self.get_queryset().get(id=key).fans.all().order_by('-fans__create_time')
        elif type == 'followings':
            self.serializer_class = UserFollowingsModelSerializer
            queryset = self.get_queryset().get(id=key).following_users.all().order_by('-create_time')
        else:
            self.serializer_class = ArticleModelSerializer
            queryset = self.get_queryset().get(id=key).collection_articles.all().order_by('-create_time')
        queryset = self.filter_queryset(queryset)
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)
